﻿using System.Net;
using System.Text;
using System.Xml.Linq;
using Network.Tcp;

namespace Network.StepProtocol;

public class StepPackageReader
{
    public StepPackageReader(IStepPackageFactory stepPackageFactory, long sessionID, EndPoint? ipAddress)
    {
        StepPackageFactory = stepPackageFactory;
        SessionID = sessionID;
        IPAddress = ipAddress;
    }
    public bool AppendMessage(TcpEvent tcpEvent)
    {
        if (tcpEvent.Buff == null)
            return false;
        if (RecvBuff == null)
        {
            RecvBuff = tcpEvent.Buff[tcpEvent.ReadIndex..(tcpEvent.ReadIndex + tcpEvent.Length)];
        }
        else
        {
            RecvBuff = RecvBuff.Concat(tcpEvent.Buff[tcpEvent.ReadIndex..(tcpEvent.ReadIndex + tcpEvent.Length)]).ToArray();
        }
        return true;
    }
    public bool ParsePackage(out StepPackageBase? stepPackage)
    {
        stepPackage = null;
        if (RecvBuff == null || RecvBuff.Length < StepUtility.StepHeadLen)
        {
            return true;
        }
		if (!StepUtility.GetPackageStart(RecvBuff, 0, RecvBuff.Length, out int packageStartIndex))
        {
            Console.WriteLine("Cannot Find PackageStart Mark.");
            return false;
        }
        if (RecvBuff.Length - packageStartIndex < StepUtility.StepHeadLen)
        {
            return true;
        }
        Head = new StepHead();
        if (!StepUtility.HeadFromStream(RecvBuff, packageStartIndex, packageStartIndex + StepUtility.StepHeadLen, Head))
        {
            return false;
        }
        if ((RecvBuff.Length - packageStartIndex) < Head.BodyLen + StepUtility.StepHeadLen + StepUtility.StepTailLen)
        {
            return true;
        }
        Tail = new StepTail();
        if (!StepUtility.TailFromStream(RecvBuff, packageStartIndex + StepUtility.StepHeadLen + Head.BodyLen, packageStartIndex + StepUtility.StepHeadLen + Head.BodyLen + StepUtility.StepTailLen, Tail))
        {
            return false;
        }
        var checkSum = StepUtility.CalculateSum(RecvBuff, packageStartIndex, packageStartIndex + StepUtility.StepHeadLen + Head.BodyLen);
        if (checkSum != Tail.CheckSum)
        {
            Console.WriteLine($"CheckSum Not Match. Tail.CheckSum:{Tail.CheckSum}, CalculateSum:{checkSum}");
            return false;
        }
        stepPackage = StepPackageFactory.CreateStepPackage(Head.PackageID);
        if (stepPackage == null)
        {
            return false;
        }
        stepPackage.SessionID = SessionID;
        stepPackage.IPAddress = IPAddress;

        stepPackage.Head = Head;
        stepPackage.Tail = Tail;
        var ret = stepPackage.FromProtocolStream(RecvBuff, packageStartIndex + StepUtility.StepHeadLen, packageStartIndex + StepUtility.StepHeadLen + Head.BodyLen);
        RecvBuff = RecvBuff.Skip(packageStartIndex + StepUtility.StepHeadLen + Head.BodyLen + StepUtility.StepTailLen).ToArray();
        return ret;
    }

    private IStepPackageFactory StepPackageFactory;
    private long SessionID;
    private EndPoint? IPAddress;
    private StepHead? Head;
    private StepTail? Tail;
    private byte[]? RecvBuff;
}
